﻿/************************************************************************

   Extended Silverlight Toolkit

   Copyright (C) 2010-2012 Xceed Software Inc.

   This program is provided to you under the terms of the Microsoft Public
   License (Ms-PL) as published at http://extendedsilverlight.codeplex.com/license

   Please purchase a commercial version of this toolkit if you are using
   it in a commercial product. The commercial versions support the project,
   and also include more features for each control, priority support,
   source code, updates, removed watermark, and a proprietary license.

   Visit http://xceed.com and follow @datagrid on Twitter.

  **********************************************************************/

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;

namespace Xceed.Silverlight.ListBox
{
  public abstract class IndicatorBase : Control
  {
    #region Constructor
    internal IndicatorBase()
    {
    }
    #endregion

    #region Minimum Property

    public static readonly DependencyProperty MinimumProperty = DependencyProperty.Register(
      "Minimum",
      typeof( double ),
      typeof( IndicatorBase ),
      new PropertyMetadata( 0d ) );

    public double Minimum
    {
      get
      {
        return ( double )this.GetValue( IndicatorBase.MinimumProperty );
      }
      set
      {
        this.SetValue( IndicatorBase.MinimumProperty, value );
      }
    }

    #endregion

    #region Maximum Property

    public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register(
      "Maximum",
      typeof( double ),
      typeof( IndicatorBase ),
      new PropertyMetadata( 1d ) );

    public double Maximum
    {
      get
      {
        return ( double )this.GetValue( IndicatorBase.MaximumProperty );
      }
      set
      {
        this.SetValue( IndicatorBase.MaximumProperty, value );
      }
    }

    #endregion

    #region AnimatedValue Property

    public static readonly DependencyProperty AnimatedValueProperty = DependencyProperty.Register(
      "AnimatedValue",
      typeof( object ),
      typeof( IndicatorBase ),
      new PropertyMetadata( null ) );

    public object AnimatedValue
    {
      get
      {
        return ( object )this.GetValue( IndicatorBase.AnimatedValueProperty );
      }
      set
      {
        this.SetValue( IndicatorBase.AnimatedValueProperty, value );
      }
    }

    #endregion

    #region AnimationDuration Property

    public static readonly DependencyProperty AnimationDurationProperty = DependencyProperty.Register(
      "AnimationDuration",
      typeof( int ),
      typeof( IndicatorBase ),
      new PropertyMetadata( 1000 ) );

    public int AnimationDuration
    {
      get
      {
        return ( int )this.GetValue( IndicatorBase.AnimationDurationProperty );
      }
      set
      {
        this.SetValue( IndicatorBase.AnimationDurationProperty, value );
      }
    }

    #endregion

    #region RefreshRate Property

    public static readonly DependencyProperty RefreshRateProperty = DependencyProperty.Register(
      "RefreshRate",
      typeof( int ),
      typeof( IndicatorBase ),
      new PropertyMetadata( 30,
        new PropertyChangedCallback( IndicatorBase.OnRefreshRateChanged ) ) );

    public int RefreshRate
    {
      get
      {
        return ( int )this.GetValue( IndicatorBase.RefreshRateProperty );
      }
      set
      {
        this.SetValue( IndicatorBase.RefreshRateProperty, value );
      }
    }

    private static void OnRefreshRateChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      IndicatorBase indicator = sender as IndicatorBase;

      if( indicator == null )
        return;

      indicator.OnRefreshRateChanged( ( int )e.OldValue, ( int )e.NewValue );
    }

    #endregion

    #region FadeOutAnimationDuration Property

    public static readonly DependencyProperty FadeOutAnimationDurationProperty = DependencyProperty.Register(
      "FadeOutAnimationDuration",
      typeof( int ),
      typeof( IndicatorBase ),
      new PropertyMetadata( 0,
        new PropertyChangedCallback( IndicatorBase.OnFadeOutAnimationDurationChanged ) ) );

    public int FadeOutAnimationDuration
    {
      get
      {
        return ( int )this.GetValue( IndicatorBase.FadeOutAnimationDurationProperty );
      }
      set
      {
        this.SetValue( IndicatorBase.FadeOutAnimationDurationProperty, value );
      }
    }

    private static void OnFadeOutAnimationDurationChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      IndicatorBase indicator = sender as IndicatorBase;

      if( indicator == null )
        return;

      indicator.OnFadeOutAnimationDurationChanged( ( int )e.OldValue, ( int )e.NewValue );
    }

    #endregion

    internal void OnFadeOutAnimationDurationChanged( int oldValue, int newValue )
    {
      if( m_killTimer != null )
        m_killTimer.Interval = TimeSpan.FromMilliseconds( newValue );
    }

    internal void OnRefreshRateChanged( int oldValue, int newValue )
    {
      if( ( m_timer != null ) && ( newValue > 0 ) )
      {
        m_timer.Interval = TimeSpan.FromMilliseconds( 1000 / newValue );
      }
    }

    internal void StartTimer()
    {
      if( m_timer == null )
      {
        m_timer = new DispatcherTimer();
        m_timer.Tick += this.OnTimerTick;

        int refreshRate = this.RefreshRate;

        if( refreshRate > 0 )
          m_timer.Interval = TimeSpan.FromMilliseconds( 1000 / refreshRate );
      }

      if( !m_timer.IsEnabled )
        m_timer.Start();
    }

    internal void StopTimer()
    {
      if( m_timer == null )
        return;

      m_timer.Stop();
    }

    internal void StartKillTimer()
    {
      if( m_killTimer == null )
      {
        m_killTimer = new DispatcherTimer();
        m_killTimer.Tick += this.OnKillTimerTick;

        int refreshRate = this.RefreshRate;

        if( refreshRate > 0 )
          m_killTimer.Interval = TimeSpan.FromMilliseconds( 1000 / refreshRate );
      }

      if( !m_killTimer.IsEnabled )
        m_killTimer.Start();
    }

    internal void StopKillTimer()
    {
      if( m_killTimer == null )
        return;

      m_killTimer.Stop();
    }

    internal void OnTimerTick( object sender, EventArgs e )
    {
      int oldTickCount = m_tickCounts;
      m_tickCounts = Environment.TickCount;
      double minimum = this.Minimum;

      m_ratio = ( m_ratio + ( ( double )( m_tickCounts - oldTickCount ) / ( double )this.AnimationDuration ) ) % 1;

      this.AnimatedValue = minimum + ( m_ratio * ( this.Maximum - minimum ) );
    }

    internal virtual void OnKillTimerTick( object sender, EventArgs e )
    {
      this.StopTimer();
      this.StopKillTimer();
    }

    #region Private fields

    private DispatcherTimer m_timer = null;
    private DispatcherTimer m_killTimer = null;
    private double m_ratio = 0;
    private int m_tickCounts = Environment.TickCount;

    #endregion
  }
}
